﻿#include "OperGraphPick.h"

// Qt
#include <QAction>

// VTK
#include <vtkActor.h>

// App
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"

// Graph
#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActor.h"
#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActor2D.h"
#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActorImage.h"
#include "FITK_Component/FITKAcousticsVTKGraphAdaptor/FITKAcousticsVTKGraphObject3D.h"
#include "FITK_Component/FITKAcousticsVTKGraphAdaptor/FITKAcousticsVTKGraphActor.h"

// Render
#include "FITK_Component/FITKRenderWindowVTK/FITKGraph3DWindowVTK.h"
#include "FITK_Component/FITKRenderWindowVTK/FITKGraphRender.h"
#include "FITK_Component/FITKRenderWindowVTK/FITKGraphObjectVTK.h"

// Graph data manager
#include "GraphDataProvider/GraphProviderManager.h"
#include "GraphDataProvider/GraphModelProvider.h"
#include "GraphDataProvider/GraphMarkProvider.h"

// GUI
#include "GUIFrame/MainWindow.h"
#include "GUIFrame/CentralWidget.h"
#include "GUIWidget/GraphArea.h"
#include "GUIWidget/PreWindow3D.h"
#include "FITK_Component/FITKWidget/FITKMdiArea.h"

// Pick
#include "PickDataProvider/GUIPickInfo.h"
#include "PickDataProvider/PickedDataProvider.h"

// Operator
#include "FITK_Kernel/FITKCore/FITKActionOperator.h"

namespace GUIOper
{
    OperGraphPick::OperGraphPick()
    {
        // 初始化拾取数据管理器。
        m_pickedProvider = GraphData::PickedDataProvider::getInstance();
    }

    OperGraphPick::~OperGraphPick()
    {

    }

    void OperGraphPick::picked(Comp::FITKGraph3DWindowVTK* graphWindow, vtkActor* actor, int index, double* pickedWorldPos)
    {
        if (!graphWindow || !actor)
        {
            return;
        }

        // 处理拾取数据。
        m_pickedProvider->addPicked(actor, index, pickedWorldPos);

        // 刷新窗口。
        graphWindow->reRender();
    }

    void OperGraphPick::picked(Comp::FITKGraph3DWindowVTK* graphWindow, vtkActor2D* actor)
    {
        if (!graphWindow || !actor)
        {
            return;
        }

        // 处理拾取数据。
        m_pickedProvider->addPicked(actor);

        // 刷新窗口。
        graphWindow->reRender();
    }

    void OperGraphPick::picked(Comp::FITKGraph3DWindowVTK* graphWindow, vtkImageActor* actor)
    {
        if (!graphWindow || !actor)
        {
            return;
        }

        // 处理拾取数据。
        m_pickedProvider->addPicked(actor);

        // 刷新窗口。
        graphWindow->reRender();
    }

    void OperGraphPick::picked(Comp::FITKGraph3DWindowVTK* graphWindow, QList<vtkActor*> actors, vtkPlanes* pickPlanes)
    {
        if (!graphWindow || !pickPlanes || actors.count() == 0)
        {
            return;
        }

        // 处理拾取数据。
        m_pickedProvider->addPicked(actors, pickPlanes);

        // 刷新窗口。
        graphWindow->reRender();
    }

    void OperGraphPick::doublePicked(vtkActor* actor, int index)
    {
        if (!actor)
        {
            return;
        }

        // 获取可视化对象。
        FITKAcousticsVTKGraphActor* fActor = dynamic_cast<FITKAcousticsVTKGraphActor*>(actor);
        if (!fActor)
        {
            return;
        }

        Exchange::FITKAcousticsVTKGraphObject3D* gObj = fActor->getGraphObjectAs<Exchange::FITKAcousticsVTKGraphObject3D>();

        // 处理双击逻辑。
        dealWithDoubleClick(gObj, index);
    }

    void OperGraphPick::doublePicked(vtkActor2D* actor)
    {
        if (!actor)
        {
            return;
        }

        // 获取可视化对象。
        FITKGraphActor2D* fActor2D = dynamic_cast<FITKGraphActor2D*>(actor);
        if (!fActor2D)
        {
            return;
        }

        Exchange::FITKAcousticsVTKGraphObject3D* gObj = fActor2D->getGraphObjectAs<Exchange::FITKAcousticsVTKGraphObject3D>();

        // 处理双击逻辑。
        dealWithDoubleClick(gObj);
    }

    void OperGraphPick::doublePicked(vtkImageActor* actor)
    {
        if (!actor)
        {
            return;
        }

        // 获取可视化对象。
        FITKGraphActorImage* fActorImg = dynamic_cast<FITKGraphActorImage*>(actor);
        if (!fActorImg)
        {
            return;
        }

        Exchange::FITKAcousticsVTKGraphObject3D* gObj = fActorImg->getGraphObjectAs<Exchange::FITKAcousticsVTKGraphObject3D>();

        // 处理双击逻辑。
        dealWithDoubleClick(gObj);
    }

    void OperGraphPick::dealWithDoubleClick(Exchange::FITKAcousticsVTKGraphObject3D* gObj, int index)
    {
        if (!gObj)
        {
            return;
        }

        // 获取对象类型。
        QString operKey;
        QAction* actTemp = new QAction;
        Exchange::FITKAcousticsVTKCommons::AcousticsGraphType gType = gObj->getGraphInfo().Type;

        int dataId = -1;

#if SUBSYSTEM_MERGE
        switch (gType)
        {
            // 融合数据。
        case Exchange::FITKAcousticsVTKCommons::ShellGraph:
        case Exchange::FITKAcousticsVTKCommons::CavityGraph:
        case Exchange::FITKAcousticsVTKCommons::JunctionLine:
        case Exchange::FITKAcousticsVTKCommons::JunctionArea:
        case Exchange::FITKAcousticsVTKCommons::FEFaceGraph:
        case Exchange::FITKAcousticsVTKCommons::FEStructureShellGraph:
        case Exchange::FITKAcousticsVTKCommons::FEStructureBeamGraph:
        case Exchange::FITKAcousticsVTKCommons::FEAcousticGraph:
        {
            // 提取数据ID。
            dataId = gObj->getShapeIdByVTKCellId(index);
            break;
        }
        // 独立数据。
        case Exchange::FITKAcousticsVTKCommons::BeamGraph:
        case Exchange::FITKAcousticsVTKCommons::SemiInfFluid:
        case Exchange::FITKAcousticsVTKCommons::JunctionPoint:
        case Exchange::FITKAcousticsVTKCommons::LoadPointForceGraph:
        case Exchange::FITKAcousticsVTKCommons::LoadPowerGraph:
        case Exchange::FITKAcousticsVTKCommons::LoadConstraintGraph:
        case Exchange::FITKAcousticsVTKCommons::LoadImportGraph:
        case Exchange::FITKAcousticsVTKCommons::LoadExcForMomGraph:
        case Exchange::FITKAcousticsVTKCommons::LoadMonopoleGraph:
        case Exchange::FITKAcousticsVTKCommons::SensorGraph:
        {
            // 获取数据对象ID。
            dataId = gObj->getDataId();
            break;
        }
        default:
            break;
        }
#else
        // 获取数据对象ID。
        dataId = gObj->getDataId();
#endif

        if (dataId <= 0)
        {
            return;
        }

        switch (gType)
        {
        case Exchange::FITKAcousticsVTKCommons::BeamGraph:
        {
            // SEA梁。
            operKey = "actionEditBeam";
            break;
        }
        case Exchange::FITKAcousticsVTKCommons::ShellGraph:
        {
            // SEA壳（板）。
            operKey = "actionEditPlate";
            break;
        }
        case Exchange::FITKAcousticsVTKCommons::CavityGraph:
        {
            // SEA声腔。
            operKey = "actionEditCavity";
            break;
        }
        case Exchange::FITKAcousticsVTKCommons::SemiInfFluid:
        {
            // 半无限流体。
            operKey = "actionEditSemiInfiniteFluid";
            break;
        }
        case Exchange::FITKAcousticsVTKCommons::JunctionPoint:
        {
            // 连接点。
            operKey = "actionEditJunctionPoint";
            break;
        }
        case Exchange::FITKAcousticsVTKCommons::JunctionLine:
        {
            // 连接线。
            operKey = "actionEditJunctionLine";
            break;
        }
        case Exchange::FITKAcousticsVTKCommons::JunctionArea:
        {
            // 连接面。
            operKey = "actionEditJunctionArea";
            break;
        }
        case Exchange::FITKAcousticsVTKCommons::LoadPointForceGraph:
        case Exchange::FITKAcousticsVTKCommons::LoadPowerGraph:
        case Exchange::FITKAcousticsVTKCommons::LoadConstraintGraph:
        case Exchange::FITKAcousticsVTKCommons::LoadImportGraph:
        case Exchange::FITKAcousticsVTKCommons::LoadExcForMomGraph:
        case Exchange::FITKAcousticsVTKCommons::LoadMonopoleGraph:{
            // 编辑载荷
            operKey = "actionEditLoad";
            break;
        }
        case Exchange::FITKAcousticsVTKCommons::FEFaceGraph: {
            operKey = "actionEditLoad";
            break;
        }
        case Exchange::FITKAcousticsVTKCommons::FEStructureShellGraph: 
        case Exchange::FITKAcousticsVTKCommons::FEStructureBeamGraph: 
        case Exchange::FITKAcousticsVTKCommons::FEAcousticGraph: {
            operKey = "actionEditFESubsystem";
            break;
        }
        case Exchange::FITKAcousticsVTKCommons::SensorGraph: {
            operKey = "actionEditFESensor";
            break;
        }
        default:
            break;
        }

        actTemp->setObjectName(operKey);
        Core::FITKActionOperator* oper = FITKOPERREPO->getOperatorT<Core::FITKActionOperator>(operKey);
        if (oper)
        {
            // 设置数据ID。
            oper->setArgs("DataID", dataId);

            // 设置发射器对象。
            oper->setEmitter(actTemp);

            // 触发操作器功能。
            oper->actionTriggered();
        }

        // 析构临时Action。
        delete actTemp;
    }

    void OperGraphPick::clear(Comp::FITKGraph3DWindowVTK* graphWindow)
    {
        // 清空拾取数据。
        GraphData::PickedDataProvider::getInstance()->clearPickedData();

        // 刷新窗口。
        graphWindow = graphWindow == nullptr ? getCurrentGraphWindow() : graphWindow;
        if (graphWindow)
        {
            graphWindow->reRender();
        }
    }

    void OperGraphPick::setActorStateByPickInfo(int pickObjType, int pickMethod, int dataObjId)
    {
        GUI::GUIPickInfo::PickObjType pObjType = GUI::GUIPickInfo::PickObjType(pickObjType);
        GUI::GUIPickInfo::PickMethod pMethod = GUI::GUIPickInfo::PickMethod(pickMethod);
        Q_UNUSED(pMethod);

        // 获取模型与符号可视化对象管理器。
        Comp::FITKGraph3DWindowVTK* graphWindow = getCurrentGraphWindow();
        GraphData::GraphModelProvider* modelProvider = GraphData::GraphProviderManager::getInstance()->getModelProvider(graphWindow);
        GraphData::GraphMarkProvider* markProvider = GraphData::GraphProviderManager::getInstance()->getMarkProvider(graphWindow);
        if (modelProvider == nullptr || markProvider == nullptr)return;

        //关闭所有拾取状态
        modelProvider->setGeoNonePickable();
        modelProvider->setMeshCellPickable(false);
        modelProvider->setDiscNodesPickable(false);
        modelProvider->setSEABeamPickable(false);
        modelProvider->setSEAShellPickable(false);
        modelProvider->setSEACavityPickable(false);
        modelProvider->setSEASemiInfFluidPickable(false);
        modelProvider->setFEFacePickable(false);
        modelProvider->setFEShellsPickable(false);
        modelProvider->setFEBeamsPickable(false);
        modelProvider->setFEAcousticPickable(false);
        modelProvider->setSensorsPickable(false);
        markProvider->setSEAJunctionsPickable(false);
        markProvider->setFEJunctionsPickable(false);
        markProvider->setHybridJunctionsPickable(false);
        markProvider->setLoadsPickable(false);

        // 通过可视化对象管理器获取数据并设置状态。
        switch (pObjType)
        {
        case GUI::GUIPickInfo::POBJAll:
        {
            modelProvider->setGeoPickable(dataObjId);
            modelProvider->setGeoSolidPickable(dataObjId);
            modelProvider->setMeshCellPickable(true, dataObjId);
            modelProvider->setDiscNodesPickable(true, dataObjId);
            modelProvider->setDoubleClickPickable(true);
            markProvider->setDoubleClickPickable(true);
            break;
        }
        case GUI::GUIPickInfo::POBJAllExceptModel:
        {
            modelProvider->setGeoNonePickable();
            modelProvider->setMeshCellPickable(false);
            modelProvider->setDiscNodesPickable(true);
            modelProvider->setDoubleClickPickable(true);
            markProvider->setDoubleClickPickable(true);
            break;
        }       
        case GUI::GUIPickInfo::POBJGeometryVert:
        {
            modelProvider->setGeoVertPickable(dataObjId);
            modelProvider->setMeshCellPickable(false, dataObjId);
            modelProvider->setDiscNodesPickable(false, dataObjId);
            modelProvider->setDoubleClickPickable(false);
            markProvider->setDoubleClickPickable(false);
            break;
        }
        case GUI::GUIPickInfo::POBJGeometryEdge:
        {
            modelProvider->setGeoEdgePickable(dataObjId);
            modelProvider->setMeshCellPickable(false, dataObjId);
            modelProvider->setDiscNodesPickable(false, dataObjId);
            modelProvider->setDoubleClickPickable(false);
            markProvider->setDoubleClickPickable(false);
            break;
        }
        case GUI::GUIPickInfo::POBJGeometryFace:
        {
            modelProvider->setGeoFacePickable(dataObjId);
            modelProvider->setMeshCellPickable(false);
            modelProvider->setDiscNodesPickable(false);
            modelProvider->setDoubleClickPickable(false);
            markProvider->setDoubleClickPickable(false);
            break;
        }
        case GUI::GUIPickInfo::POBJGeometrySolid:
        {
            modelProvider->setGeoSolidPickable();
            modelProvider->setMeshCellPickable(false);
            modelProvider->setDiscNodesPickable(false);
            modelProvider->setDoubleClickPickable(false);
            markProvider->setDoubleClickPickable(false);
            break;
        }
        case  GUI::GUIPickInfo::POBJGeometry:
        {
            modelProvider->setGeoPickable(dataObjId);
            break;
        }
        case GUI::GUIPickInfo::POBJMeshCell:
        case GUI::GUIPickInfo::POBJMeshCell1D:
        case GUI::GUIPickInfo::POBJMeshCell2D:
        case GUI::GUIPickInfo::POBJMeshCell3D:
        {
            modelProvider->setGeoNonePickable();
            modelProvider->setMeshCellPickable(true, dataObjId);
            modelProvider->setDiscNodesPickable(false);
            modelProvider->setDoubleClickPickable(false);
            markProvider->setDoubleClickPickable(false);
            break;
        }
        case GUI::GUIPickInfo::POBJDiscNode:
        {
            modelProvider->setGeoNonePickable();
            modelProvider->setMeshCellPickable(false);
            modelProvider->setDiscNodesPickable(true, dataObjId);
            modelProvider->setDoubleClickPickable(false);
            markProvider->setDoubleClickPickable(false);
            break;
        }
        case GUI::GUIPickInfo::POBJSEASubSystem:
        {
            modelProvider->setSEABeamPickable(true);
            modelProvider->setSEAShellPickable(true);
            modelProvider->setSEACavityPickable(true);
            modelProvider->setSEASemiInfFluidPickable(true);
            break;
        } 
        case GUI::GUIPickInfo::POBJSEABeam:
        {
            modelProvider->setSEABeamPickable(true);
            break;
        }
        case GUI::GUIPickInfo::POBJSEAShell:
        {
            modelProvider->setSEAShellPickable(true);
            break;
        }
        case GUI::GUIPickInfo::POBJSEACavity:
        {
            modelProvider->setSEACavityPickable(true);
            break;
        }
        case GUI::GUIPickInfo::POBJSEAShellAndCavity:
        {
            modelProvider->setSEAShellPickable(true);
            modelProvider->setSEACavityPickable(true);
            break;
        }
        case GUI::GUIPickInfo::POBJSEASemiInfFluid:
        {
            modelProvider->setSEASemiInfFluidPickable(true);
            break;
        }
        case GUI::GUIPickInfo::POBJJunctions:
        {
            markProvider->setSEAJunctionsPickable(true);
            markProvider->setFEJunctionsPickable(true);
            markProvider->setHybridJunctionsPickable(true);
            break;
        }
        case GUI::GUIPickInfo::POBJSEAJunctions:
        {
            markProvider->setSEAJunctionsPickable(true);
            break;
        }
        case GUI::GUIPickInfo::POBJSEAJunctionPoint:
        {
            markProvider->setSEAJunctionPointPickable(true);
            break;
        }
        case GUI::GUIPickInfo::POBJSEAJunctionLine:
        {
            markProvider->setSEAJunctionLinePickable(true);
            break;
        }
        case GUI::GUIPickInfo::POBJSEAJunctionArea:
        {
            markProvider->setSEAJunctionAreaPickable(true);
            break;
        }
        case GUI::GUIPickInfo::POBJLoadAll:
        {
            markProvider->setLoadsPickable(true);
            break;
        }
        // FE面
        case GUI::GUIPickInfo::POBJFEFace: {
            modelProvider->setFEFacePickable(true);
            break;
        }
        //FE结构
        case GUI::GUIPickInfo::POBJFEStructure: {
            modelProvider->setFEShellsPickable(true);
            modelProvider->setFEBeamsPickable(true);
            break;
        }
        //FE声腔
        case GUI::GUIPickInfo::POBJFEAcoustic: {
            modelProvider->setFEAcousticPickable(true);
            break;
        }
        //FE传感器
        case GUI::GUIPickInfo::POBJSensor: {
            modelProvider->setSensorsPickable(true);
            break;
        }
        //全部子系统
        case GUI::GUIPickInfo::POBJSubSystem: {
            modelProvider->setSEABeamPickable(true);
            modelProvider->setSEAShellPickable(true);
            modelProvider->setSEACavityPickable(true);
            modelProvider->setSEASemiInfFluidPickable(true);
            modelProvider->setFEFacePickable(true);
            modelProvider->setFEShellsPickable(true);
            modelProvider->setFEBeamsPickable(true);
            modelProvider->setFEAcousticPickable(true);
            modelProvider->setSensorsPickable(true);
            break;
        }
        case GUI::GUIPickInfo::POBJSubSysOutBeamSemiFEFaceSensor: {
            modelProvider->setSEAShellPickable(true);
            modelProvider->setSEACavityPickable(true);
            modelProvider->setFEShellsPickable(true);
            modelProvider->setFEAcousticPickable(true);
            break;
        }
        default:
        {
            // 关闭全部拾取状态（启用双击可视化对象拾取状态）。
            modelProvider->setDoubleClickPickable(true);
            markProvider->setDoubleClickPickable(true);
            break;
        }
        }
    }

    void OperGraphPick::addGraphObjToRenderWindow(Exchange::FITKAcousticsVTKGraphObject3D* obj, Comp::FITKGraph3DWindowVTK* graphWindow)
    {
        if (!obj || !graphWindow)
        {
            return;
        }

        // 获取渲染层级。
        int layer = obj->getRenderLayer();

        // 设置渲染器（计算渲染尺寸）
        Comp::FITKGraphRender* render = graphWindow->getRenderer(layer);
        if (!render)
        {
            return;
        }

        obj->setFITKRender(render);

        // 先移除，防止在不同窗口进行多次渲染。
        Comp::FITKGraph3DWindowVTK* lastGraphWindow = dynamic_cast<Comp::FITKGraph3DWindowVTK*>(obj->getGraphWidget());
        obj->removeFromGraphWidget();

        if (lastGraphWindow)
        {
            lastGraphWindow->reRender();
        }

        // 添加可视化对象。
        graphWindow->addObject(layer, obj, false);

        // 存储渲染窗口。
        obj->setGraphWidget(graphWindow);
    }

    Comp::FITKGraph3DWindowVTK* OperGraphPick::getCurrentGraphWindow()
    {
        // 获取主窗口。
        GUI::MainWindow* mainWindow = FITKAPP->getGlobalData()->getMainWindowT<GUI::MainWindow>();
        if (!mainWindow)
        {
            return nullptr;
        }

        // 获取中心区域。
        GUI::CentralWidget* centralWidget = mainWindow->getCentralWidget();
        if (!centralWidget)
        {
            return nullptr;
        }

        // 获取3D区域。
        GUI::PreWindow3D* widget3D = centralWidget->getGraphArea()->getCurrentWindow<GUI::PreWindow3D>();
        if (!widget3D)
        {
            return nullptr;
        }

        //获取3D可视化区域
        Comp::FITKGraph3DWindowVTK* graphWidget = widget3D->getRenderWindow();
        if (!graphWidget)
        {
            return nullptr;
        }

        return graphWidget;
    }
}  // namespace GUIOper